package hyl.base.flow.chart;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 
 * <p>
 * className: AThrough
 * </p>
 * <p>
 * Description: 不依赖节点自有遍历方法的外部遍历引擎 根类
 * </p>
 * 
 * @author: 37798
 * @date: 2021年5月29日 下午5:06:54
 * @copyright: 2018 da you zou Inc. All rights reserved.
 */
public class CThrough {

	/**
	 * 遍历引擎可以有多个工作者,每个工作者有独立的工作
	 */
	protected List<IWorker> _workers = new ArrayList<>();
	// 处理计数器,每流经一个节点,加一
	protected AtomicInteger _流经节点数 = new AtomicInteger(0);
	// 处理计数器每加工完成一个节点,加一
	protected AtomicInteger _处理节点数 = new AtomicInteger(0);

	/**
	 * @param 添加环路上的工作单元
	 */
	public void addWork(IWorker worker) {
		_workers.add(worker);
	}

	/**
	 * 移除工作
	 * 
	 * @param worker
	 */
	public void removeWork(IWorker worker) {
		_workers.remove(worker);
	}

	/**
	 * 工作开始前重置
	 */
	protected void reset() {
		_流经节点数.set(0);
		_处理节点数.set(0);
	}

	public int getThroughCount() {
		return _流经节点数.get();
	}

	public int getWorkingCount() {
		return _处理节点数.get();
	}
	/**
	 * 是否要求工作必须有结果 ,如果没有结果是否立即停止遍历
	 */
	public boolean isCheck=false;
	/**
	 * // 最大遍历深度
	 */
	protected int _maxdepth = 0; // 负数和0 表示不限制 1 表示限制遍历一层 n 限制遍历n层

	public void set最大遍历深度(int 遍历深度) {
		_maxdepth = 遍历深度;
	}

	protected Map<String, String> _whereMap = new HashMap<>();

	public void set遍历终止条件(String 属性, String 值) {
		_whereMap.put(属性, 值);
	}

	/**
	 * 判断工作是否可以执行
	 * 
	 * @param node
	 * @param 深度
	 * @return false 不能执行 true 可以执行
	 */
	protected boolean enable(INode node, int 深度) {
		if (_maxdepth > 0 && _maxdepth == 深度)
			return false;
		if (node == null)
			return false;
		_流经节点数.incrementAndGet();
		// 判断执行条件是否满足 如果满足执行,否则不执行
		if (!_whereMap.isEmpty()) {
			for (Entry<String, String> item : _whereMap.entrySet()) {
				if (!node.hasAttr(item.getKey(), item.getValue())) {// 节点不匹配,不执行
					return false;
				}
			}
		}
		return true;
	}

	/**
	 * 让所有工作人员开始围绕某个节点进行加工
	 *
	 * 返回true 终止遍历
	 */
	protected boolean process(int layer, INode node) throws Exception {
		// 判断执行条件是否满足 如果满足执行,否则不执行
		if (!_workers.isEmpty()) {
			for (IWorker wk : _workers) {
				Object ob = wk.run(node, null, layer); // 出现异常则标记为false
				if (ob == null)
					return true;
			}
			_处理节点数.incrementAndGet();
		}
		return false;
	}

	/**
	 * 线上遍历
	 * 
	 * @param 深度
	 * @param node
	 * @throws Throwable
	 */
	protected void up(int 深度, INode node) throws Throwable {
		if (!enable(node, 深度))
			return;

		if (process(深度, node)&&isCheck)
			return;
		++深度;
		if (node == null) {
			return;
		}

		for (INode snode : node.getParents()) {
			up(深度, snode);
		}

	}

	/**
	 * 向下遍历
	 * 
	 * @param 深度
	 * @param node
	 * @throws Exception
	 */
	protected void down(int 深度, INode node) throws Exception {
		if (!enable(node, 深度))
			return;
		if (process(深度, node)&&isCheck)
			return;
		深度++;
		if (node == null) {
			return;
		}

		for (INode snode : node.getChilds()) {
			// 如果反馈结果是false 停止遍历
			down(深度, snode);
		}

	}

	/**
	 * 开始向上遍历
	 */
	public void througUp(INode 第一个节点) {
		if (_workers.isEmpty())
			return;
		_maxdepth = 0;
		try {
			reset();
			up(0, 第一个节点);
		} catch (Throwable e) {
			e.printStackTrace();
		}

	}

	/**
	 * 开始向下遍历
	 * 
	 * @param 第一个节点
	 */
	public void througDown(INode 第一个节点) {
		if (_workers.isEmpty())
			return;
		_maxdepth = 0;
		try {
			reset();
			down(0, 第一个节点);
		} catch (Throwable e) {
			e.printStackTrace();
		}
	}

}
